﻿using Castle.Core.Configuration;
using Castle.Core.Logging;
using Castle.MicroKernel;
using Castle.MicroKernel.Registration;
using Inovout.Components;
using Inovout.Models;
using Inovout.Repositories;
using Inovout.Services;
using System;
using System.IO;
using System.Linq;
using System.Reflection;

namespace Inovout.Services
{
    public class ServiceComponentRegistrar : ComponentRegistrar
    {
        public override void Register()
        {
            IConfiguration dataSourceConfiguration = Application.Configuration.Children.SingleOrDefault(c => c.Name.Equals("dataSource"));
            if (dataSourceConfiguration != null)
            {
                Container.Kernel.ConfigurationStore.AddFacilityConfiguration(typeof(NHibernateExtensionFacility).FullName
                    , NHibernateExtensionFacility.GetNHibernateFacilityConfiguration(dataSourceConfiguration));
                Container.AddFacility<NHibernateExtensionFacility>();
            }
            Container.Register(
                Component.For(typeof(IRepository<>))
                    .ImplementedBy(typeof(DataObjectRepository<>))
                    .LifeStyle.Transient
                    .OnCreate(BuildRepository),
                Component.For(typeof(IRepositoryService<>))
                    .ImplementedBy(typeof(RepositoryService<>))
                    .LifeStyle.Transient
                    .OnCreate(BuildService)
                );
        }
        public override void Register(Assembly assembly)
        {
            //先注册通用类型，再注册继承类型并设置为默认服务接口。
            Container.Register(
                Classes.FromAssembly(assembly)
                    .BasedOn<DataInitiator>()
                    .WithServiceBase(),
                Classes.FromAssembly(assembly)
                    .BasedOn(typeof(IRepository<>))
                    .WithServiceSelf()
                    .WithServiceAllInterfaces()
                    .Configure(
                        component => component.LifeStyle.Transient.OnCreate(BuildRepository)
                            .IsDefault().IsGenericParameterConstraints()
                    ),
                Classes.FromAssembly(assembly)
                    .BasedOn(typeof(BaseService))
                    .WithService.AllInterfaces()
                    .WithServiceSelf()
                    .Configure(
                        component => component.LifeStyle.Transient.OnCreate(BuildService)
                            .IsDefault().IsGenericParameterConstraints()
                    ),
                Classes.FromAssembly(assembly)
                    .BasedOn(typeof(IRepositoryService<>))
                    .WithService.AllInterfaces()
                    .WithServiceSelf()
                    .Configure(
                        component => component.LifeStyle.Transient.OnCreate(BuildService)
                            .IsDefault().IsGenericParameterConstraints()
                    ),
                Classes.FromAssembly(assembly)
                    .BasedOn(typeof(DataObject))
                    .WithService.Base()
                    .WithService.AllInterfaces()
                    .Configure((component) =>
                    {
                        component.LifeStyle.Transient.Named(component.Implementation.ToString());

                    })
                );
            RegisterNHibernateMappingClass(assembly);

        }
        private void RegisterNHibernateMappingClass(Assembly assembly)
        {
            bool existsDataObject = false;
            //因为某些类为抽象类，Windsor会忽略这些抽象类，故需单独查找继承自DataObject的类型
            foreach (Type dataObjectType in assembly.GetTypes().Where(t => typeof(DataObject).IsAssignableFrom(t)))
            {
                existsDataObject = true;
                //Type dataObjectType = component.Implementation;
               RepositoryConfigurationKeyDictionary repositoryConfigurationKeyDictionary
                    = Container.Resolve<RepositoryConfigurationKeyDictionary>();
                NHibernate.Cfg.Configuration configuration
                    = Container.Resolve<NHibernate.Cfg.Configuration>(
                    repositoryConfigurationKeyDictionary.GetDatabaseName(dataObjectType) + ".cfg");
                Stream cfgStream = null;
                if (assembly.GetManifestResourceInfo(dataObjectType.FullName + ".hbm.xml") == null)
                {
                    cfgStream = assembly.GetManifestResourceStream(dataObjectType.FullName);
                }
                else
                {
                    cfgStream =
                    assembly.GetManifestResourceStream(dataObjectType.FullName + ".hbm.xml");
                }
                if (cfgStream != null)
                {
                    using (cfgStream)
                    {
                        configuration.AddInputStream(cfgStream);
                    }
                }
            }
            if (existsDataObject)
            {
                //因为间接依赖程序不会被默认加载，会引发NH的一些异常
                foreach (var assemblyName in assembly.GetReferencedAssemblies())
                {
                    Assembly.Load(assemblyName);
                }
            }
        }

        private void BuildService(IKernel kernel, object instance)
        {
            BaseService service = instance as BaseService;
            if (service.Logger == null)
            {
                service.Logger = kernel.Resolve<IExtendedLogger>();
            }
            Type modelType = GetModelType(service.GetType());
            if (service.repository == null && modelType != null)
            {

                Type repositoryType = typeof(IRepository<>);
                repositoryType = repositoryType.MakeGenericType(modelType);
                service.repository = kernel.Resolve(repositoryType) as BaseRepository;
            }
        }
        private void BuildRepository(IKernel kernel, object instance)
        {
            BaseRepository repository = instance as BaseRepository;
            if (repository.Logger == null)
            {
                repository.Logger = kernel.Resolve<IExtendedLogger>();
            }
            if (repository.sessionManager == null)
            {
                repository.sessionManager = kernel.Resolve<ITypeSessionManager>();
            }
        }
        private static Type GetModelType(Type serviceType)
        {
            Type repositoryServiceInterfaceType = serviceType.GetInterface(typeof(IRepositoryService<>).Name);

            if (repositoryServiceInterfaceType == null)
            {
                return null;
            }
            else
            {
                return repositoryServiceInterfaceType.GetGenericArguments()[0];
            }
        }
    }
}
